package com.example.opengldemo._camera_demo;

import android.media.MediaCodec;
import android.media.MediaFormat;
import android.opengl.EGLSurface;

import com.example.opengldemo._camera_demo.handle.HardMediaData;
import com.example.opengldemo._camera_demo.handle.IHardStore;
import com.example.opengldemo._camera_demo.renderer.RenderBean;
import com.example.opengldemo.util.CodecUtil;

import java.nio.ByteBuffer;

public class SurfaceEncoder extends SurfaceShower {

    private MediaConfig mConfig=new MediaConfig();
    private MediaCodec mVideoEncoder;
    private boolean isEncodeStarted=false;
    private static final int TIME_OUT=1000;

    private IHardStore mStore;
    private int mVideoTrack=-1;

    private OnDrawEndListener mListener;
    private long startTime=-1;

    public SurfaceEncoder(){
        super.setOnDrawEndListener(new OnDrawEndListener() {
            @Override
            public void onDrawEnd(EGLSurface surface, RenderBean bean) {

                if(bean.timeStamp!=-1){
                    bean.egl.setPresentationTime(surface,bean.timeStamp*1000);
                }else{
                    if(startTime==-1){
                        startTime=bean.textureTime;
                    }
                    bean.egl.setPresentationTime(surface,bean.textureTime-startTime);
                }
                videoEncodeStep(false);

                if(mListener!=null){
                    mListener.onDrawEnd(surface,bean);
                }
            }
        });
    }

    private synchronized boolean videoEncodeStep(boolean isEnd){

        if(isEncodeStarted){
            if(isEnd){
                mVideoEncoder.signalEndOfInputStream();
            }
            MediaCodec.BufferInfo info=new MediaCodec.BufferInfo();
            while (true){
                int mOutputIndex=mVideoEncoder.dequeueOutputBuffer(info,TIME_OUT);

                if(mOutputIndex>=0){
                    if((info.flags&MediaCodec.BUFFER_FLAG_CODEC_CONFIG)!=0){
                        info.size=0;
                    }
                    ByteBuffer buffer= CodecUtil.getOutputBuffer(mVideoEncoder,mOutputIndex);
                    if(mStore!=null){
                        mStore.addData(mVideoTrack,new HardMediaData(buffer,info));
                    }
                    mVideoEncoder.releaseOutputBuffer(mOutputIndex,false);
                    if((info.flags&MediaCodec.BUFFER_FLAG_END_OF_STREAM)!=0){
                        closeVideoEncoder();
                        isEncodeStarted=false;
                        break;
                    }
                }else if(mOutputIndex== MediaCodec.INFO_OUTPUT_FORMAT_CHANGED){
                    MediaFormat format=mVideoEncoder.getOutputFormat();
                    if(mStore!=null){
                        mVideoTrack=mStore.addTrack(format);
                    }
                }else if(mOutputIndex== MediaCodec.INFO_TRY_AGAIN_LATER&&!isEnd){
                    break;
                }
            }
        }
        return false;
    }

    private void closeVideoEncoder(){
        if(mVideoEncoder!=null){
            mVideoEncoder.stop();
            mVideoEncoder.release();
            mVideoEncoder=null;
        }
    }

}
